import { FieldManager } from './components';
import * as util from './util';
import { isQualityRuleField, isQualityInfoField, isCurrencyField, getDependenciesFieldNameMap } from '@service/FieldService.ts'
import { findComponentsDownward } from '@src/util/assist'
import { isEmpty } from '@src/util/type';
import { uuid } from 'pub-bbx-utils';
import { isOpenLinkCardGray } from '@src/util/grayInfo';
import { debounce } from 'lodash'
import { useFormMultiLanguage } from '@hooks/useFormMultiLanguage'
const { internationalGray } = useFormMultiLanguage()
import i18n from '@src/locales'
import { needRowForOneEnum, dontNeedMarginForBox, needPaddingForBox, getformItemClass } from '@src/component/form/util'

function getFormFieldComponent(field, comp, mode) {
  // 检测是否有扩展
  let extend = comp.extend || {}
  let key = `${mode}_${field.fieldName}_build`
  let systemKey = `${mode}_${field.formType}_build`
  if(extend[key] || extend[systemKey]) {
    return extend[key] || extend[systemKey]
  }
  
  if(null == comp.build) return null
  
  return comp.build
}

function createFormField(h, field, comp, mode) {
  const component = getFormFieldComponent(field, comp, mode)
  if(null == component) return null
  
  let data = {
    props: getProps(field, this),
    on: {
      update: event => {
        this.clearDependenciesFieldValue(event)
        this.$emit('update', event)
        this.triggerConnectorUpdate(event)
      },
      getDeleteFiles: (value) => {
        this.$emit('getDeleteFiles',value)
      }
    }
  }
  return h(component, data);
}

function getValue(field, ctx) {
  // 质保规则/质保信息字段
  if (isQualityRuleField(field) || isQualityInfoField(field)) {
    return ctx.value[field.fieldName] || {}
  }

  // 货币金额字段
  if (isCurrencyField(field)) {
    let value = ctx.value[field.fieldName];
    if(typeof(value) === 'string' || isEmpty(value)) {
      return { number: field.defaultValue || '', currency: field?.setting?.defaultCurrency || 'CNY' };
    }
    return ctx.value[field.fieldName]
  }

  if(field.formType === 'select' && !field.isSystem && field.setting) {
    const { dataSource, isMulti } = field.setting;
    const fieldValue = ctx.value[field.fieldName];
    if(isMulti && dataSource && !isEmpty(fieldValue)) {
      if(!Array.isArray(fieldValue)) {
        // 部分旧数据存在isMulti = true，但是value是字符串的问题
        ctx.value[field.fieldName] = [fieldValue]
      }
      return ctx.value[field.fieldName].filter(item => dataSource.includes(item))
    }
  }
  
  // TODO 如果是时间字段需要家冗余字段要在这里处理
  return ctx.value[field.fieldName]
}

function getProps(field, ctx) {
  let props = {
    field,
    isEdit: ctx.isEdit,
    serviceQualityStatus: ctx.serviceQualityStatus,
    settlementRulesList: ctx.settlementRulesList,
    productIds: ctx.productIds,
    value: getValue(field, ctx),
    formEditingMode: ctx.formEditingMode,
    intelligentConfigNew: ctx.intelligentConfig,
    mode: ctx.mode
    
  }
  
  // 质保信息字段
  if (isQualityInfoField(field)) {
    props.productCatalogId = ctx.value?.catalogId?.[0]?.id || ctx.value?.catalogId?.id
    props.formData = ctx.value
  }
  // TODO 国际化灰度开启
  if(internationalGray) {
    props.totalCurrency = ctx.totalCurrency
    props.taskId = ctx.taskId
  }
  
  
  return props
}

const FormBuilder = {
  name: 'form-builder',
  props: {
    fields: {
      type: Array,
      default: () => []
    },
    value: {
      type: Object,
      default: () => ({})
    },
    mode: {
      type: String,
      default: ''
    },
    cardType:{
      type:String,
      default:''
    },
    serviceQualityStatus: {
      type:String,
      default:''
    },
    isEdit: {
      type: Boolean,
      default: false
    },
    extraValidations: {
      type: Object,
      default: () => ({})
    },
    // 表单状态，新建或编辑
    formStatus: {
      type: String
    },
    isValidateByParent: {
      type: Boolean,
      default: true
    },
    // 工单结算规则数据
    settlementRulesList: {
      type: Object,
      default: () => ({})
    },
    isSampleValid: {

    },
    totalCurrency: {
      type: String,
      default: 'CNY'
    },
    taskId: {
      type: String,
      default: ''
    },
    // 工单附加组件单次多次标识
    cardInputType: {
      type: String,
      default: ''
    },
    /** 工单关联产品ids */
    productIds: {
      type: Array,
      default: () => ([])
    },
    formCellCount:{
      type: Number,
      default: 1
    },
    // 表单操作模式
    formEditingMode: {
      type: String,
      default: '', // create | edit
    },
    intelligentConfig: {
      type: Object,
      default: () => ({})
    }
  },
  data(){
    return {
      /* 远程验证数据 */
      remoteValidateData: {
        // 字段
        field: null,
        // 方法
        validateFunc: null,
      },
      // 所有注册的验证方法
      validateMap: {},
      componentKey: uuid(),
      // 连接器组件列表
      connectorComponents: [],
    }
  },
  computed: {
    childFormBuilderComponents() {
      return findComponentsDownward(this, 'form-builder')
    },
    dependenciesFieldNameMap() {
      return getDependenciesFieldNameMap(this.fields)
    },
    fieldNameMap() {
      return (
        this.fields.reduce(
          (acc, field) => {
            acc[field.fieldName] = field
            return acc
          }, 
          {}
        )
      )
    },
    formBuilderClass() { 
      let baseClass = ['form-builder']
      if (this.formCellCount > 1) {
        // 多列布局
        baseClass = [...baseClass, `bbx-cell-form-box-${this.formCellCount}`, 'bbx-cell-form-box']
      }
      return baseClass
    }
  },
  watch: {
    fields: {
      handler() {
        this.$nextTick(() => {
          this.findConnectorComponent()
        })
      }
    }
  },
  methods: {
    // 外部调用，更改物料返还数据
    handlerMaterialReturnOutSide(data, type){
      /** 
       * data 是当前我修改的那条物料核销的数据
       * type 目前存在的情况 'delete', 'edit', 'snChange',未定义
       * type === delete 代表删除了某条物料核销 
       * type === edit 代表改变了某条物料核销的被替换物料 
       * type === snChange 代表改变了某条物料核销的SN
       * type === 未定义 代表改变了某条物料核销的被替换物料SN 
       * 以下逻辑的前提是物料返还有数据，且 当前改变的物料核销数据是带有 被替换物料SN 这种唯一标识的。
       * 其他的 被替换物料SN  不存在的物料核销数据改变了则不做处理。
       */
      if (!this.value?.materialReturn?.length) return
      
      if(!type){
        if(data.snManage === '是' && data.SN) {
          this.value.materialReturn.forEach(item => {
            const initMaterialSN = item.initMaterialSN || item.attribute?.initMaterialSN
            if(initMaterialSN === data.SN){
              item.SN = data.replacedMaterialSN
              item.replacedMaterialSN = data.replacedMaterialSN
            }
          })
        }
      }

      if(type === 'delete'){
        if(data.snManage === '是' && data.SN) {
          this.value.materialReturn = this.value.materialReturn.filter(item => (item.initMaterialSN || item.attribute?.initMaterialSN) !== data.SN)
        }
      }

      if(type === 'edit'){
        if(data.snManage === '是' && data.SN) {
          this.value.materialReturn.forEach(item => {
            const initMaterialSN = item.initMaterialSN || item.attribute?.initMaterialSN
            if(initMaterialSN === data.SN){
              Object.keys(data.replacedMaterial).forEach(val => {
                if(item.hasOwnProperty(val)){
                  item[val] = data.replacedMaterial[val]
                }
              })
              item.SN = ''
              item.replacedMaterialSN = ''
              item.isReplaced = true
              item.num = item.num ?? 1
            }
          })
        }
      }

      if(type === 'snChange'){
        this.value.materialReturn = this.value.materialReturn.filter(item => (item.initMaterialSN || item.attribute?.initMaterialSN) !== data.SN)
      }
    },

    updateRelation(fields) {
      this.validate(this.isSampleValid, fields)
    },
    clearDependenciesFieldValue(event) {
      const { field = {}, newValue } = event
      const { fieldName = '' } = field
      
      this.clearDependenciesFieldValueImpl(fieldName, newValue)
      
    },
    clearDependenciesFieldValueImpl(fieldName, newValue) {
      if (!this.dependenciesFieldNameMap[fieldName]) return
      
      const dependenciesFieldNameMap = this.dependenciesFieldNameMap[fieldName]
      
      Object.keys(dependenciesFieldNameMap).forEach(dependenciesFieldName => {
        
        if (this.dependenciesFieldNameMap[dependenciesFieldName]) {
          this.clearDependenciesFieldValueImpl(dependenciesFieldName, newValue)
        }
        
        const dependenciesValues = dependenciesFieldNameMap[dependenciesFieldName]
        
        if (!dependenciesValues.includes(newValue)) {
          const field = this.fieldNameMap[dependenciesFieldName]
          const formValue = util.initialize([field], {})
          
          this.$emit('update', {
            newValue: formValue[dependenciesFieldName],
            field
          })
          
        }
        
      })
    },
    /** 获取该dom元素 */
    findRootEl() {
      return this.$el;
    },
    /**
     * 检测所有字段的结果，都验证通过，返回true, 否则返回false
     */
    validate(isSample = true, fields) {
      const allFormBuilderComponentsValidateMap = this.getAllFormBuilderComponentsValidateMap()
      
      const allValidates = Object.keys(allFormBuilderComponentsValidateMap)
      const validatePromises = allValidates.filter(key => !fields || fields.includes(key)).map(key => {
        return allFormBuilderComponentsValidateMap[key](isSample)
      })
      
      // 用于非formbuilder创建的表单项校验（templater中的），或其他自定义校验
      let promises2 = Object.keys(this.extraValidations).filter(type => {
        return ((!fields || fields.includes(type)) && this.extraValidations.ifRequired(type))
      }).map(type => {
        
        return new Promise((resolve, reject) => {
          let res
          let fn = this.extraValidations[type]
          fn && (res = fn())
          resolve(res)
        })
        
      })
      
      return Promise.all(validatePromises.concat(promises2))
        .then(results => results.every(msg => !msg))
        .catch(err => console.error('validate error', err))
    },
    /** 注册待验证的组件 */
    addFieldHandler(event){
      event.stopPropagation();
      let { fieldName, validate } = event.detail;
      if (event.detail && event.detail.field && event.detail.field.formType === 'info') {
        return;
      }
      if (validate) {
        this.validateMap[fieldName] = validate;
      }
    },
    removeFieldHandler(event){
      event.stopPropagation();
      
      let {fieldName} = event.detail;
      delete this.validateMap[fieldName];
    },
    outsideSetRemoteValidateData(data) {
      this.$set(this, 'remoteValidateData', data)
    },
    getAllFormBuilderComponentsValidateMap() {
      let allFormBuilderValidateMap = {}
      
      this.childFormBuilderComponents
        // 过滤仅需要被父级组件校验的formBuilder组件
        .filter(formBuilderComponent => formBuilderComponent.isValidateByParent)
        .forEach(childFormBuilderComponent => {
          allFormBuilderValidateMap = Object.assign(allFormBuilderValidateMap, childFormBuilderComponent.validateMap)
        })
      
      allFormBuilderValidateMap = Object.assign(allFormBuilderValidateMap, this.validateMap)
      
      return allFormBuilderValidateMap
    },
    rerender() {
      this.componentKey = uuid()
    },
    findConnectorComponent() {

      if (isOpenLinkCardGray()) {
        const connectorComponents = findComponentsDownward(this, 'form-connector')
        this.connectorComponents = connectorComponents
      }

    },
    triggerConnectorUpdateImpl(event) {

      if (!isOpenLinkCardGray()) {
        console.warn('[form-builder]: triggerConnectorUpdate is not open connectorFormControl gray')
        return
      }

      const field = event?.field || {}

      this.connectorComponents.forEach(connectorComponent => {
        connectorComponent.updateConnectorDataByRelationField(field)
      })

    },
    triggerConnectorUpdate: debounce(function(event) {
      this.triggerConnectorUpdateImpl(event)
    }, 500),
  
  },
  render(h){
    let count = 0;
    let formGroups = util.expandField(this.fields).map(field => {
      
      
      let fieldName = field.fieldName;
      let defaultValueConfig = field.setting?.defaultValueConfig

      // 服务商编辑信息时隐藏判断是否是已隐藏字段（下面也有isHidden判断隐藏的，但是）
      if(['service_provider_edit', 'service_engineer_edit', 'projectType'].includes(this.mode) && field.isHidden === 1) return null;

      if(this.$slots[fieldName]) {
        count = 0
        field['isCellLast'] = false
        return (this.$slots[fieldName]) ;
      }
        
      if(this.$scopedSlots[fieldName]) {
        count = 0
        field['isCellLast'] = false
        return (this.$scopedSlots[fieldName]({field, value: getValue(field, this)})) ;
      }
        
      // 判读是否隐藏该字段
      if(this.mode !== 'qualitySetting' && util.isHiddenField(field, this.value, this.fields)) {
        return null;
      }
        
      // 判断是否是已隐藏字段
      if(field.isHidden == 1) return null;
        
      // 判断是否可见
      // if(field.isVisible == false && field.formType !== 'formula') return null;

      if(field.isVisible == false && field.formType !== 'formula') return null;

        
      // 判断下是否是客户产品关联字段
      let formType = 'relationCustomer' || 'relationProduct'
      let isUser = field.setting && (field.setting.formType === 'user' || field.setting.fieldName === 'customerManager')
      if (this.$scopedSlots[formType] && isUser && field.isShow) {
        count = 0
        field['isCellLast'] = false
        return (
          this.$scopedSlots[formType]({field, value: getValue(field, this)})
        )
      }
      let comp = FieldManager.findField(field.formType);
      if(comp == null) {
        console.warn(`[not implement]: ${field.displayName}(${field.fieldName}): ${field.formType}. `)
        return null;
      }
        
      let formField
      if(field.setting?.autoGeneration) {
        field.isNull = 1
        if (this.formStatus === 'edit') {
          formField = <div class="form-item__text">{getValue(field, this)}</div>
        } else {
          formField = <div class="form-item__text">{i18n.t('common.form.build.createAfterSystem', {data1:field.displayName})}</div>
        }
      } else {
        const mode = this.mode;
        // if (field.formType === 'attachment') {
        //   debugger
        // }
        formField = createFormField.call(this, h, field, comp, mode);
      }
      if(comp.formType == 'separator' || field.formType === 'info' || null == formField) {
        if (comp.formType == 'separator') {
          const groups = util.groupField(this.fields, this.value, true)
          const isHiddenSeparator = util.isHiddenSeparator(groups, this.value, this.fields, fieldName, true)
          // 当前分割线分组字段都不显示时，分割线不显示
          if (isHiddenSeparator) return null
        }
        count++;
        if(needRowForOneEnum.includes(field.formType)){
          count = 0
          field['isCellLast'] = false
        }else{
          if(count == this.formCellCount && this.formCellCount > 1){
            field['isCellLast'] = true
            count = 0
          }else{
            field['isCellLast'] = false
          }
        }
        return (
          <div class={getformItemClass(field, false, this.formCellCount)}>
            {formField}
          </div>
        );
      }
        
      
        
      let cardType = this.cardType;
        
      // TODO: 临时做法，之后修改
      if (isQualityInfoField(field)) {
        count++;
        if(needRowForOneEnum.includes(field.formType)){
          count = 0
          field['isCellLast'] = false
        }else{
          if(count == this.formCellCount && this.formCellCount > 1){
            field['isCellLast'] = true
            count = 0
          }else{
            field['isCellLast'] = false
          }
        }
        return (
          <div class={getformItemClass(field, false, this.formCellCount)}>
            {formField}
          </div>
        )
      }
        
      // 显示标题
      const displayName = comp.isShowDisplayName === false ? '' : field?.displayName;
      count++;
        if(needRowForOneEnum.includes(field.formType)){
          count = 0
          field['isCellLast'] = false
        }else{
          if(count == this.formCellCount && this.formCellCount > 1){
            field['isCellLast'] = true
            count = 0
          }else{
            field['isCellLast'] = false
          }
        }
      // 计算公式不显示的时候，计算逻辑未更新修复
      const key = field?.link ? `${field.fieldName}_${Math.random()}` : field.fieldName
      return (
        <form-item
          style={(field.isVisible == false && field.formType === 'formula') ? 'display: none' : ''}
          updateRelation={this.updateRelation}
          form={field.isNullRelationFields ? this.value : void 0}
          ref={field.fieldName}
          label={displayName} 
          formCellCount={this.formCellCount} 
          cardType={cardType}
          key={key}
          findRootEl={this.findRootEl} 
          validation
        >
          { formField }
        </form-item>
      );
    })
      .filter((vnode, index, arr) => {
        // 过滤不渲染节点
        if(null == vnode) return false;
        
        let options = vnode.componentOptions || {};
        // 非分割线字段直接显示
        if(options.tag != 'form-separator') return true;
        // 只有在下一个元素存在且不是分割线时，才显示该分割线
        // 如果该节点后面没有非分割线字段，则不显示
        for(let i = index + 1; i < arr.length; i++){
          let next = arr[i];
          if(next == null) continue;
          
          let nextOptions = next.componentOptions || {};
          return nextOptions.tag != 'form-separator';
        }
        
        // 默认返回false, 走到这里意味着后面的节点都是null
        return false;
      });
      
    return (
      <div>
        <div class={this.formBuilderClass} key={this.componentKey}>
          {this.$slots.default}
          {formGroups}
        </div>
      </div>
      
    )
  },
  mounted(){
    this.$el.addEventListener('form.add.field', this.addFieldHandler)
    this.$el.addEventListener('form.remove.field', this.removeFieldHandler)

    this.$nextTick(() => {
      this.findConnectorComponent()
    })

  },
  destroyed(){
    this.$el.removeEventListener('form.add.field', this.addFieldHandler);
    this.$el.removeEventListener('form.remove.field', this.removeFieldHandler)
  }
};

export default FormBuilder;
